/*
 *  Project:            Network_Tester_v0.1.
 *  Module name:        Network_Tester_Top.
 *  Description:        Top Module of Network_Tester_hardware.
 *  Last updated date:  2023.04.19.
 *
 *  Copyright (C) 2023 Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright and related rights are licensed under the MIT license.
 *
 *  Noted:
 *    1) rgmii2gmii & gmii_rx2rgmii are processed by language templates;
 *    2) rgmii_rx is constrained by set_input_delay "-2.0 ~ -0.7";
 *    3) 134b pkt data definition: 
 *      [133:132] head tag, 2'b01 is head, 2'b10 is tail;
 *      [131:128] valid tag, 4'b1111 means sixteen 8b data is valid;
 *      [127:0]   pkt data, invalid part is padded with 0;
 *    4) the riscv-32imc core is a modified cv32e40p;
 *
 *  Space = 2;
 */

`timescale 1ns / 1ps

module Network_Tester_Top(
  //* system input, clk;
   input               sys_clk
  ,input               rst_n
  //* rgmii port;
  ,output  wire        mdio_mdc
  ,inout               mdio_mdio_io
  ,output  wire        phy_reset_n
  ,input         [3:0] rgmii_rd
  ,input               rgmii_rx_ctl
  ,input               rgmii_rxc
  ,output  wire  [3:0] rgmii_td
  ,output  wire        rgmii_tx_ctl
  ,output  wire        rgmii_txc

  //* rgmii port 2;
  ,output  wire        mdio_mdc_1
  ,inout               mdio_mdio_io_1
  ,output  wire        phy_reset_n_1
  ,input         [3:0] rgmii_rd_1
  ,input               rgmii_rx_ctl_1
  ,input               rgmii_rxc_1
  ,output  wire  [3:0] rgmii_td_1
  ,output  wire        rgmii_tx_ctl_1
  ,output  wire        rgmii_txc_1

  //* rgmii port 3;
  ,output  wire        mdio_mdc_2
  ,inout               mdio_mdio_io_2
  ,output  wire        phy_reset_n_2
  ,input         [3:0] rgmii_rd_2
  ,input               rgmii_rx_ctl_2
  ,input               rgmii_rxc_2
  ,output  wire  [3:0] rgmii_td_2
  ,output  wire        rgmii_tx_ctl_2
  ,output  wire        rgmii_txc_2
  
  //* rgmii port 4;
  ,output  wire        mdio_mdc_3
  ,inout               mdio_mdio_io_3
  ,output  wire        phy_reset_n_3
  ,input         [3:0] rgmii_rd_3
  ,input               rgmii_rx_ctl_3
  ,input               rgmii_rxc_3
  ,output  wire  [3:0] rgmii_td_3
  ,output  wire        rgmii_tx_ctl_3
  ,output  wire        rgmii_txc_3

  //* uart rx/tx from/to host;
  ,input               uart_rx      //* fpga receive data from host;
  ,output  wire        uart_tx      //* fpga send data to host;
  ,input               uart_cts
  ,output  wire        uart_rts
  ,input               uart_rx_1    //* fpga receive data from host;
  ,output  wire        uart_tx_1    //* fpga send data to host;
  ,input               uart_cts_1
  ,output  wire        uart_rts_1
);

  //======================= internal reg/wire/param declarations =//
  //* clock & locker;
  wire                  clk_125m, clk_50m;
  wire                  locked;     //* locked =1 means generating 125M clock successfully;

  //* system reset signal, low is active;
  wire                  sys_rst_n;
  assign                sys_rst_n     = rst_n & locked;

  //* connected wire (TODO,...)
  //* speed_mode, clock_speed, mdio (gmii_to_rgmii IP)
  wire    [1:0]         speed_mode, clock_speed;
  wire                  mdio_gem_mdc, mdio_gem_o, mdio_gem_t;
  wire                  mdio_gem_i;
  
  //* assign phy_reset_n = 1, haven't been used;
  assign                phy_reset_n   = rst_n;
  assign                phy_reset_n_1 = rst_n;
  assign                phy_reset_n_2 = rst_n;
  assign                phy_reset_n_3 = rst_n;
  //* assign mdio_mdc = 0, haven't been used;
  assign                mdio_mdc      = 1'b0;
  assign                mdio_mdc_1    = 1'b0;
  assign                mdio_mdc_2    = 1'b0;
  assign                mdio_mdc_3    = 1'b0;
  //==============================================================//

  //======================= clk wiz          =====================//
  //* gen 125M clock (Xilinx ip: clk_wiz);
  `ifdef SIM_ENV
    fake_clk_wiz_0 clk_to_125m(
      //* Clock out ports
      .clk_out1           (clk_125m             ),  //* output 125m;
      .clk_out2           (clk_50m              ),  //* output 25m;
      //* Status and control signals
      .reset              (!rst_n               ),  //* input reset
      .locked             (locked               ),  //* output locked
      // Clock in ports
      .clk_in1            (sys_clk              )
      // .clk_in1_p       (sys_clk_p            ),  //* input clk_in1_p
      // .clk_in1_n       (sys_clk_n            )   //* input clk_in1_n
    );
  `else
    clk_wiz_0 clk_to_125m(
      //* Clock out ports
      .clk_out1           (clk_125m             ),  //* output 125m;
      .clk_out2           (clk_50m              ),  //* output 25m;
      //* Status and control signals
      .reset              (!rst_n               ),  //* input reset
      .locked             (locked               ),  //* output locked
      // Clock in ports
      .clk_in1            (sys_clk              )
      // .clk_in1_p       (sys_clk_p            ),  //* input clk_in1_p
      // .clk_in1_n       (sys_clk_n            )   //* input clk_in1_n
    );
  `endif
  //==============================================================//
  
  (* mark_debug = "true"*)wire          [3:0]         w_pktData_valid_um;
  (* mark_debug = "true"*)wire          [133:0]       w_pktData_um[3:0];
  (* mark_debug = "true"*)wire          [3:0]         w_pktData_valid_gmii;
  (* mark_debug = "true"*)wire          [133:0]       w_pktData_gmii[3:0];
  wire            w_err_pktData_valid;
  wire  [133:0]   w_err_pktData;
  (* mark_debug = "true"*)wire  [31:0]    w_crc_sendPkt;

  //======================= soc_runtime      =====================// 
  //* rgmii <==> 134b pkt (without metadata);
  //* configure port;
  soc_runtime runtime_port_0(
    .clk_125m             (clk_125m                     ),
    .sys_rst_n            (sys_rst_n                    ),
    //* rgmii input;
    .rgmii_rd             (rgmii_rd                     ),  //* input
    .rgmii_rx_ctl         (rgmii_rx_ctl                 ),  //* input
    .rgmii_rxc            (rgmii_rxc                    ),  //* input
    //* rgmii output;
    .rgmii_txc            (rgmii_txc                    ),  //* output
    .rgmii_td             (rgmii_td                     ),  //* output
    .rgmii_tx_ctl         (rgmii_tx_ctl                 ),  //* output
    //* um;
    .pktData_valid_gmii   (w_pktData_valid_gmii[0]      ),
    .pktData_gmii         (w_pktData_gmii[0]            ),
    .pkt_length_gmii      (                             ),
    .ready_in             (1'b1                         ),
    .pktData_valid_um     (w_pktData_valid_um[0]        ),
    .pktData_um           (w_pktData_um[0]              ),
    //* crc;
    .i_crc_toCheck_enable (1'b0                         ),
    .i_crc_toCheck        (32'b0                        ),
    .o_crc_sendPkt        (                             )
  );

  //* sender
  soc_runtime runtime_port_1(
    .clk_125m             (clk_125m                     ),
    .sys_rst_n            (sys_rst_n                    ),
    //* rgmii input;
    .rgmii_rd             (rgmii_rd_1                   ),  //* input
    .rgmii_rx_ctl         (rgmii_rx_ctl_1               ),  //* input
    .rgmii_rxc            (rgmii_rxc_1                  ),  //* input
    //* rgmii output;
    .rgmii_txc            (rgmii_txc_1                  ),  //* output
    .rgmii_td             (rgmii_td_1                   ),  //* output
    .rgmii_tx_ctl         (rgmii_tx_ctl_1               ),  //* output
    //* um;
    .pktData_valid_gmii   (w_pktData_valid_gmii[1]      ),
    .pktData_gmii         (w_pktData_gmii[1]            ),
    .pkt_length_gmii      (                             ),
    .ready_in             (1'b1                         ),
    .pktData_valid_um     (w_pktData_valid_um[1]        ),
    .pktData_um           (w_pktData_um[1]              ),
    //* crc;
    .i_crc_toCheck_enable (1'b0                         ),
    .i_crc_toCheck        (32'b0                        ),
    .o_crc_sendPkt        (w_crc_sendPkt                )
  );

  //* receiver
  soc_runtime runtime_port_2(
    .clk_125m             (clk_125m                     ),
    .sys_rst_n            (sys_rst_n                    ),
    //* rgmii input;
    .rgmii_rd             (rgmii_rd_2                   ),  //* input
    .rgmii_rx_ctl         (rgmii_rx_ctl_2               ),  //* input
    .rgmii_rxc            (rgmii_rxc_2                  ),  //* input
    //* rgmii output;
    .rgmii_txc            (rgmii_txc_2                  ),  //* output
    .rgmii_td             (rgmii_td_2                   ),  //* output
    .rgmii_tx_ctl         (rgmii_tx_ctl_2               ),  //* output
    //* um;
    .pktData_valid_gmii   (w_pktData_valid_gmii[2]      ),
    .pktData_gmii         (w_pktData_gmii[2]            ),
    .pkt_length_gmii      (                             ),
    .ready_in             (1'b1                         ),
    .pktData_valid_um     (w_pktData_valid_um[2]        ),
    .pktData_um           (w_pktData_um[2]              ),
    //* crc;
    .i_crc_toCheck_enable (1'b1                         ),
    .i_crc_toCheck        (w_crc_sendPkt                ),
    .o_crc_sendPkt        (                             )
  );

  // //* monitor
  // soc_runtime runtime_port_3(
  //   .clk_125m             (clk_125m                     ),
  //   .sys_rst_n            (sys_rst_n                    ),
  //   //* rgmii input;
  //   .rgmii_rd             (rgmii_rd_3                   ),  //* input
  //   .rgmii_rx_ctl         (rgmii_rx_ctl_3               ),  //* input
  //   .rgmii_rxc            (rgmii_rxc_3                  ),  //* input
  //   //* rgmii output;
  //   .rgmii_txc            (rgmii_txc_3                  ),  //* output
  //   .rgmii_td             (rgmii_td_3                   ),  //* output
  //   .rgmii_tx_ctl         (rgmii_tx_ctl_3               ),  //* output
  //   //* um;
  //   .pktData_valid_gmii   (w_pktData_valid_gmii[3]      ),
  //   .pktData_gmii         (w_pktData_gmii[3]            ),
  //   .pkt_length_gmii      (                             ),
  //   .ready_in             (1'b1                         ),
  //   .pktData_valid_um     (w_pktData_valid_um[3]        ),
  //   .pktData_um           (w_pktData_um[3]              )
  // );

  //======================= Tester_Conf & sender =================//
  Tester_Conf Tester_Conf_inst(
   .i_clk                 (clk_125m                     ),
   .i_rst_n               (sys_rst_n                    ),
   .i_data_valid          (w_pktData_valid_gmii[0]      ),
   .i_data                (w_pktData_gmii[0]            ),
   //* send pkt
   .o_data_valid          (w_pktData_valid_um[0]        ),
   .o_data                (w_pktData_um[0]              ),
   .o_data_send_valid     (w_pktData_valid_um[1]        ),
   .o_data_send           (w_pktData_um[1]              ),
   //* err pkt 
   .i_err_data_valid      (w_pktData_valid_gmii[2]      ),
   .i_err_data            (w_pktData_gmii[2]            )
  );

  assign  w_pktData_valid_um[3] = 1'b0;
  assign  w_pktData_um[3]       = 134'b0;
  assign  w_pktData_valid_um[2] = 1'b0;
  assign  w_pktData_um[2]       = 134'b0;

  //======================= PE_ARRAY         =====================//
//  PE_ARRAY PE_ARRAY_inst(
//    //* clock & resets;
//    .i_sys_clk            (clk_125m                     ),
//    .i_sys_rst_n          (1'b1                         ),
//    .i_pe_clk             (clk_50m                      ),
//    .i_rst_n              (sys_rst_n                    ),
//    //* pkt from/to CPI
//    //* pkt from CPI, TODO,
//    .i_pe_conf_mac        (48'h8888_8888_8988           ),
//    .i_data_valid         (pktData_valid_gmii           ),
//    // .i_data_valid         (1'b0           ),
//    .i_data               (pktData_gmii                 ),
//    .i_meta_valid         (w_metaIn_valid               ),
//    .i_meta               (w_metaIn                     ),
//    .o_alf                (w_to_PE_alf                  ),
//    //* pkt to CPI, TODO,
//    .o_data_valid         (pktData_valid_pe             ),
//    .o_data               (w_temp_pktData_pe            ),
//    .o_meta_valid         (w_metaOut_valid              ),
//    .o_meta               (w_metaOut                    ),
//    .i_alf                (1'b0                         ),
    
//    `ifdef DUAL_CORE
//      .i_uart_rx          ({uart_rx_1, uart_rx }        ),
//      .o_uart_tx          ({uart_tx_1, uart_tx }        ),
//      .i_uart_cts         ({uart_cts_1,uart_cts}        ),
//      .o_uart_rts         ({uart_rts_1,uart_rts}        ),
//    `endif
//    //* pads;
//    .i_start_en_pad       (4'd1                         )
//  );
  //==============================================================//


endmodule
